/*
Author: Surpass-HC
Source: https://gitee.com/hxchuan000/clpc-1
Mail: surpass-hc@qq.com
*/
// for before c99
#ifndef __PROTOCOL_LIGHT_OPERATE_H__
#define __PROTOCOL_LIGHT_OPERATE_H__
#include <clptcConfig.h>
#include <clptcFunItf.h>
#if CLPTC_CPL_USE_CRYPTE
#include <sm4.h>
#endif
// protocol light
// protocol light length type
typedef uint16_t clptcLenType;

// protocol Parse Common state Enum
enum clptcPsStEnum
{
    clptcPsSt_Begin = 0, // begin to parse data
    clptcPsSt_FixHd,     // fixed head
    clptcPsSt_Vers,      // version
    clptcPsSt_Hd,        // version head
    clptcPsSt_Data,      // data
};
// protocol Parse version Enum
enum clptcPsVersEnum
{
    clptcPsVers0 = 0, // version 0
    clptcPsVers1,     // version 1
    clptcPsVers2,     // version 2
};
// PTC:protocol
#define CLPTC_PACK_PST_BEG 0  // begin position
#define CLPTC_PACK_PST_VERS 2 // version position
#define CLPTC_PV1_PST_RESP 3  // version 1 response position
// VERSION 1
#define CLPTC_PV1_PST_SIZE 4   // version 1 size position
#define CLPTC_PV1_PST_ADDR 6   // version 1 addr position
#define CLPTC_PV1_PST_CRYPTE 7 // version 1 encrypte position
#define CLPTC_PV1_PST_CMDID 8  // version 1 command position
#define CLPTC_PV1_PST_CRC1 10  // version 1 crc1 position
#define CLPTC_PV1_PST_DATA 12  // version 1 data position
// VERSION 2
// #define CLPTC_PV2PST_SIZE 4     // version 2 size position
// #define CLPTC_PV2PST_CRYPTE 8 // version 2 encrypte  position
// #define CLPTC_PV2PST_CPRS 9 // version 2 compress position
// #define CLPTC_PV2PST_RESERVE 10 // version 2 reserve position
// #define CLPTC_PV2PST_DATA 12     // version 2 data position

// protocol Parse operate struct
typedef struct
{
    clptcFunItfStc *dFunInf; // device information
#if CLPTC_CPL_HOST_ENABLE
    uint8_t hostSndInf[24];
#endif
    clptcLenType subRespSizeHostCmdId; // sub:response size; host:send cmd id
    uint8_t subRespCrypteHostAddr;     // sub:do cmd response crypte type; host:send addr.
    uint8_t subRespStatFlag;           // sub:do cmd response flag. host:deal response data result.
    clptcLenType totalsize;            // pkptr's size
    clptcLenType rcvCount;             // receive counter
    clptcLenType needSize;             // receive need size
    uint8_t parseState;                // parse state
    uint8_t ptcAddr;                   // reserve data, just for alignment.
    uint8_t pkptr[1];                  // pack buffer
} clptcParseStc;
#define clptcPsComSize (offsetof(clptcParseStc, pkptr))

#define clptcStcPtr(ptcPtr) ((clptcParseStc *)ptcPtr)

#define clptcGetMyaddr(ptcPtr) (clptcStcPtr(ptcPtr)->ptcAddr)
#define clptcSetMyaddr(ptcPtr, smyaddr) (clptcStcPtr(ptcPtr)->ptcAddr = smyaddr)
#if CLPTC_CPL_USE_CRYPTE
#define clptcGetKeyDlgPtr(ptcPtr) (clptcStcPtr(ptcPtr)->clptcKeyDlg)
#endif

#define clptcGetPackPtr(ptcPtr) (clptcStcPtr(ptcPtr)->pkptr)

#define clptcGetVers(ptcPtr) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PACK_PST_VERS])
#define clptcSetVers(ptcPtr, svers) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PACK_PST_VERS] = svers)

#define clptcGetDataSizeV1(ptcPtr) (ovtBigSys16(*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_SIZE]))))
#define clptcSetDataSizeV1(ptcPtr, ssize) (*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_SIZE])) = ovtBigSys16(ssize))

#define clptcGetHeadSizeV1 (CLPTC_PV1_PST_DATA)
#define clptcGetPackSizeV1(ptcPtr) (clptcGetHeadSizeV1 + clptcGetDataSizeV1(ptcPtr))
#define clptcGetDataMaxSizeV1(ptcPtr) (clptcStcPtr(ptcPtr)->totalsize - clptcGetHeadSizeV1)

#define clptcGetAddrV1(ptcPtr) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_ADDR])
#define clptcSetAddrV1(ptcPtr, saddr) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_ADDR] = saddr)

#define clptcGetCrypteV1(ptcPtr) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CRYPTE])
#define clptcSetCrypteV1(ptcPtr, scrp) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CRYPTE] = scrp)

#define clptcGetCmdIdV1(ptcPtr) (ovtBigSys16(*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CMDID]))))
#define clptcSetCmdIdV1(ptcPtr, sid) (*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CMDID])) = ovtBigSys16(sid))

#define clptcGetResponseV1(ptcPtr) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_RESP])
#define clptcSetResponseV1(ptcPtr, sresp) (clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_RESP] = sresp)

#define clptcGetCrc1V1(ptcPtr) (ovtBigSys16(*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CRC1]))))
#define clptcSetCrc1V1(ptcPtr, sid) (*((uint16_t *)(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_CRC1])) = ovtBigSys16(sid))

#define clptcGetDataPtrV1(ptcPtr) (&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_DATA])
#define clptcSetDataV1(ptcPtr, sbuf, ssize) (memcpypro(&clptcStcPtr(ptcPtr)->pkptr[CLPTC_PV1_PST_DATA], clptcGetDataMaxSizeV1(ptcPtr), \
                                                       sbuf, ssize),                                                                   \
                                             clptcSetDataSizeV1(ptcPtr, ssize))

clptcLenType clptcPackFinV1(void *ptcPtr);
int clptcInitV1(void *ptcPtr, clptcLenType setPackSize, clptcFunItfStc *cfgDinf);
int clptcPsDataV1(void *ptcPtr, uint8_t indata);

#if CLPTC_CPL_SUB_ENABLE
int clptcSubPsAndDeal(void *inptr, char indata);
#endif
#if CLPTC_CPL_HOST_ENABLE
// cmd master pack command function
// set data can use clptcGetDataPtrV1
int clptcHostPackCommV1(void *inptr, uint8_t saddr, uint8_t scrypte, uint16_t cmdid, clptcLenType cmdlen);
// 0:wait response, 1:ok, <0:error, >1 response error clptcCmdRespEnum
int clptcHostPsAndDeal(void *inptr, char indata);
#endif

enum clptcCmdRespEnum
{
    clptcCmdResp_OK = 0,
    clptcCmdResp_NotSndBack, // this response used to not response command.
    clptcCmdResp_NdCrypt,    // need crypte
    clptcCmdResp_EncryptErr,
    clptcCmdResp_DecryptErr,
    clptcCmdResp_NotSupport, // command not support.
    clptcCmdResp_HeartNoSpt, // heart cmd not support.
};
// protocol Parse crypte Enum
enum clptcCrpEnum
{
    clptcCrypte_None = 0,
    clptcCrypte_AesPre, // present key
    clptcCrypte_AesDlg, // dialogue key
    clptcCrypte_Rsa,
    clptcCrypte_Sm4Pre, // present key
    clptcCrypte_Sm4Dlg, // dialogue key
    clptcCrypte_Sm2,
    clptcCrypte_Des3Pre, // present key
    clptcCrypte_Des3Dlg, // dialogue key
    //
};
#endif